package com.yykj.user.center.server.service.impl.patient;

import com.alibaba.fastjson.JSONObject;
import com.yykj.common.enums.ResultEnums;
import com.yykj.common.exception.NormalException;
import com.yykj.common.service.RedisService;
import com.yykj.common.util.GsonUtil;
import com.yykj.common.util.LocalRequestUtil;
import com.yykj.common.util.LocalStringUtil;
import com.yykj.hospital.client.dto.HospitalConfigInfo;
import com.yykj.hospital.client.dto.HospitalDTO;
import com.yykj.hospital.client.dto.HospitalSettingDTO;
import com.yykj.hospital.client.feign.HospitalServerFeignClient;
import com.yykj.user.center.server.constant.Constant;
import com.yykj.user.center.server.dto.PatientCardInfoDTO;
import com.yykj.user.center.server.dto.PatientCardListDTO;
import com.yykj.user.center.server.dto.UserLoginInfo;
import com.yykj.user.center.server.form.AddPatientCardInfoForm;
import com.yykj.user.center.server.form.RemoveBindingForm;
import com.yykj.user.center.server.form.UpdatePatientCardInfoForm;
import com.yykj.user.center.server.model.PatientCardInfo;
import com.yykj.user.center.server.repository.patient.PatientCardInfoRepository;
import com.yykj.user.center.server.service.patient.PatientCardInfoService;
import com.yykj.user.center.server.utils.DateUtil;
import com.yykj.user.center.server.utils.IDCardUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author chenl
 * @version 1.0
 * @date 2021/11/1 16:48
 */
@Service
@Slf4j
public class PatientCardInfoServiceImpl implements PatientCardInfoService {
    @Autowired
    private RedisService redisService;
    @Autowired
    private PatientCardInfoRepository patientCardInfoRepository;
    @Autowired
    private HospitalServerFeignClient hospitalServerFeignClient;
    @Override
    public List<PatientCardListDTO> showPatientCardList() {
        String token = LocalRequestUtil.getToken();
        UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token),UserLoginInfo.class);
        List<PatientCardInfo> patientCardInfos =  patientCardInfoRepository.findByAccountIdAndHospitalIdAndState(userLoginInfo.getUserId(),userLoginInfo.getHospitalId(),true);
        List<PatientCardListDTO> patientCardListDTOS = new ArrayList<>();
        for(PatientCardInfo patientCardInfo:patientCardInfos){
            PatientCardListDTO patientCardListDTO = new PatientCardListDTO();
            patientCardListDTO.setId(patientCardInfo.getId());
            patientCardListDTO.setCardNo(patientCardInfo.getCardNo());
            patientCardListDTO.setRelation(patientCardInfo.getRelation());
            patientCardListDTO.setPatientName(patientCardInfo.getPatientName());
            patientCardListDTOS.add(patientCardListDTO);
        }
        return patientCardListDTOS;
    }

    @Override
    public PatientCardListDTO addPatientCard(AddPatientCardInfoForm addPatientCardInfoForm) {
        String idCard = addPatientCardInfoForm.getIdCard();
        String patientName = addPatientCardInfoForm.getPatientName();
        String relation = addPatientCardInfoForm.getRelation();
        if(StringUtils.isBlank(idCard)){
            throw new NormalException(ResultEnums.NO_IDCARD_ERROR);
        }
        if(StringUtils.isBlank(patientName)){
            throw new NormalException(ResultEnums.NO_PATIENTNAME_ERROR);
        }
        if(StringUtils.isBlank(relation)){
            throw new NormalException(ResultEnums.NO_RELATION_ERROR);
        }
        String token = LocalRequestUtil.getToken();
        UserLoginInfo userLoginInfo = GsonUtil.fromJson(redisService.get(token),UserLoginInfo.class);
        Integer hospitalId = userLoginInfo.getHospitalId();
        String userId = userLoginInfo.getUserId();
        HospitalDTO hospitalDTO = hospitalServerFeignClient.info(hospitalId);
        String code = hospitalDTO.getCode();
        LocalDateTime now = LocalDateTime.now();
        String dateString = DateUtil.dateTime2DateString(now);
        String strLast = idCard.substring(idCard.length()-4);
        String cardNo = code+dateString+strLast;
        check(hospitalId,idCard,userId,relation,patientName);
        String birthday = IDCardUtil.getBirthday(idCard);
        String sex = IDCardUtil.getSex(idCard);
        Integer age = IDCardUtil.getAge(idCard);
        //查找该身份证是否在该帐号下绑定过，绑定过则用该就诊卡号，并更新其他字段信息
        PatientCardInfo cardInfo = patientCardInfoRepository.findFirstByAccountIdAndIdCard(userId,idCard);
        PatientCardListDTO patientCardListDTO = new PatientCardListDTO();
        PatientCardInfo patientCardInfo = new PatientCardInfo();
        if(cardInfo==null){
            String id = LocalStringUtil.getUUID();
            patientCardInfo.setPatientName(patientName);
            patientCardInfo.setRelation(relation);
            patientCardInfo.setCardNo(cardNo);
            patientCardInfo.setState(true);
            patientCardInfo.setId(id);
            patientCardInfo.setAccountId(userId);
            patientCardInfo.setBirthday(birthday);
            patientCardInfo.setSex(sex);
            patientCardInfo.setIdCard(idCard);
            patientCardInfo.setAge(age);
            patientCardInfo.setHospitalId(hospitalId);
            patientCardInfoRepository.save(patientCardInfo);
            patientCardListDTO.setPatientName(patientName);
            patientCardListDTO.setRelation(relation);
            patientCardListDTO.setCardNo(cardNo);
            patientCardListDTO.setId(id);
        }else{
            String id = cardInfo.getId();
            PatientCardInfo card = patientCardInfoRepository.findById(id).orElse(null);
            card.setPatientName(patientName);
            card.setRelation(relation);
            card.setState(true);
            card.setIdCard(idCard);
            card.setBirthday(birthday);
            card.setSex(sex);
            card.setAge(age);
            card.setAccountId(userId);
            card.setHospitalId(hospitalId);
            patientCardInfoRepository.save(card);
            patientCardListDTO.setPatientName(patientName);
            patientCardListDTO.setRelation(relation);
            patientCardListDTO.setCardNo(card.getCardNo());
            patientCardListDTO.setId(id);
        }

        return patientCardListDTO;
    }

    @Override
    public Boolean removeBinding(RemoveBindingForm removeBindingForm) {
        PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(removeBindingForm.getId()).orElse(null);
        if(patientCardInfo!=null){
            patientCardInfo.setState(false);
            patientCardInfoRepository.save(patientCardInfo);
        }
        return true;
    }

    @Override
    public Boolean updatePatientCard(UpdatePatientCardInfoForm updatePatientCardInfoForm) {
        String id = updatePatientCardInfoForm.getId();
        PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(id).orElse(null);
        if(patientCardInfo!=null){
            BeanUtils.copyProperties(updatePatientCardInfoForm,patientCardInfo);
            patientCardInfoRepository.save(patientCardInfo);
        }
        return true;
    }

    @Override
    public PatientCardInfoDTO info(String id) {
        PatientCardInfoDTO patientCardInfoDTO = new PatientCardInfoDTO();
        PatientCardInfo patientCardInfo = patientCardInfoRepository.findById(id).orElse(null);
        if(patientCardInfo!=null){
            BeanUtils.copyProperties(patientCardInfo,patientCardInfoDTO);
        }
        return patientCardInfoDTO;
    }

    /**
     * 校验规则
     * 1、校验绑定就诊人数上限
     * 2、校验就诊卡关系是否存在
     * 3、校验身份证号是否与其他的用户绑定
     * 4、身份信息校验
     *
     * @return
     */
    public Boolean check(Integer hospitalId,String idCard,String accountId,String relation,String patientName){
        HospitalConfigInfo hospitalConfigInfo = hospitalServerFeignClient.hospitalConfigInfo(hospitalId);
        HospitalSettingDTO hospitalSettingDTO = hospitalConfigInfo.getHospitalSetting();
        Integer cnt = hospitalSettingDTO.getCnt();
        //根据该账号Id来查询绑定人数
        Integer count = patientCardInfoRepository.countAllByAccountIdAndState(accountId,true);
        if(cnt.intValue()==count.intValue()){
            throw new NormalException(ResultEnums.LIMIT_PATIENT_CARD_ERROR);
        }
        //校验就诊卡关系是否存在
        count = patientCardInfoRepository.countAllByRelationAndAccountIdAndIdCardAndState(relation,accountId,idCard,true);
        if(count>0){
            throw new NormalException(ResultEnums.HAS_RELATION_ERROR);
        }
        //校验身份证号是否与其他的用户绑定
        count = patientCardInfoRepository.countAllByIdCardAndState(idCard,true);
        if(count>0){
            throw new NormalException(ResultEnums.IDCARD_BINDING_ERROR);
        }
        return  isRealName(idCard,patientName);
    }


    public Boolean isRealName(String idCard,String name) {
        String host = Constant.HOST;
        String path = Constant.PATH;
        String appcode = Constant.APPCODE;
        try {
            String urlSend = host +path+ "?idCard=" + idCard + "&name="+ URLEncoder.encode(name, "UTF-8");// 【5】拼接请求链接
            URL url = new URL(urlSend);
            HttpURLConnection httpURLCon = (HttpURLConnection) url.openConnection();
            httpURLCon.setRequestProperty("Authorization", "APPCODE " + appcode);// 格式Authorization:APPCODE (中间是英文空格)
            int httpCode = httpURLCon.getResponseCode();
            log.info("httpCode is：========>{}",httpCode);
            if (httpCode == 200) {
                String json = read(httpURLCon.getInputStream());
                JSONObject jsonObject = JSONObject.parseObject(json);
                if(!"01".equals(jsonObject.get("status"))){
                    throw new NormalException(ResultEnums.IDCARD_ERROR);
                }
                log.info("身份校验，获取返回的json：{}",json);

            } else {
                Map<String, List<String>> map = httpURLCon.getHeaderFields();
                String error = map.get("X-Ca-Error-Message").get(0);
                if (httpCode == 400 && error.equals("Invalid AppCode `not exists`")) {
                    throw new NormalException(ResultEnums.REALNAME_APPCODE_ERROR);
                } else if (httpCode == 400 && error.equals("Invalid Url")) {
                    throw new NormalException(ResultEnums.REALNAME_PATH_ERROR);
                } else if (httpCode == 400 && error.equals("Invalid Param Location")) {
                    throw new NormalException(ResultEnums.REALNAME_PARAM_ERROR);
                } else if (httpCode == 403 && error.equals("Unauthorized")) {
                    throw new NormalException(ResultEnums.REALNAME_URL_ERROR);
                } else if (httpCode == 403 && error.equals("Quota Exhausted")) {
                    throw new NormalException(ResultEnums.REALNAME_NO_MONEY_ERROR);
                } else {
                    throw new NormalException(ResultEnums.REALNAME_OTHER_ERROR);
                }
            }

        } catch (MalformedURLException e) {
            throw new NormalException(ResultEnums.REALNAME_URL_FORMAT_ERROR);
        } catch (UnknownHostException e) {
            throw new NormalException(ResultEnums.REALNAME_URL_PATH_ERROR);
        }catch (NormalException e){
            Integer code = e.getCode();
            if(code==1073){
                throw new NormalException(ResultEnums.IDCARD_ERROR);
            }
        }catch (Exception e) {
            // 打开注释查看详细报错异常信息
            // e.printStackTrace();
        }
        return true;
    }
    private static String read(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String line = null;
        while ((line = br.readLine()) != null) {
            line = new String(line.getBytes(), "utf-8");
            sb.append(line);
        }
        br.close();
        return sb.toString();
    }
}
